/*
 * This file is part of the Boring Engine.
 *
 * Copyright (c) 2011 by pf5234 <pf5234@users.sourceforge.net>.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

package com.googlecode.boringengine.internal.openglrendering;

import com.sun.opengl.util.Screenshot;
import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureCoords;
import java.io.File;
import java.io.IOException;
import javax.media.opengl.GL;
import javax.media.opengl.GLException;
import javax.media.opengl.glu.GLU;
import com.googlecode.boringengine.Log;
import com.googlecode.boringengine.Sprite;
import com.googlecode.boringengine.internal.Renderer;
import java.util.ArrayList;

public class OpenGLRenderer extends Renderer {

    private int lastTarget = GL.GL_TEXTURE_2D;
    private static final ArrayList<OpenGLSprite> texturesToLoad =
            new ArrayList<OpenGLSprite>();
    private static final ArrayList<String> screenshots =
            new ArrayList<String>();

    @Override
    public void clearScreen() {
        GL gl = GLU.getCurrentGL();
        //gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        gl.glLoadIdentity();
        /*for (int i = 0; i < effects.size(); i++)
            effects.get(i).beginEffect(this);*/
        com.googlecode.boringengine.Graphics.drawRect(0, 0, 800, 600, 9);
    }

    @Override
    public void clip(int x, int y, int width, int height) {
        GL gl = GLU.getCurrentGL();
        gl.glEnable(GL.GL_SCISSOR_TEST);
        gl.glScissor(x, 600 - y - height, width, height);
    }

    @Override
    public Sprite createSpriteFromScreen(int x, int y, int w, int h) {
        OpenGLSprite s = new OpenGLSprite(Screenshot.readToBufferedImage(x, 600 - y - h, w, h, false));
        synchronized (texturesToLoad) {
            texturesToLoad.add(s);
        }
        return s;
    }

    @Override
    public Sprite createSprite(String sprite, int width, int height) {
        OpenGLSprite s = new OpenGLSprite(sprite, width, height);
        synchronized (texturesToLoad) {
            texturesToLoad.add(s);
        }
        return s;
    }

    @Override
    public void drawRect(int w, int h, int color) {
        GL gl = GLU.getCurrentGL();
        gl.glPushMatrix();
        gl.glTranslated(_x + (_flip ? w * _scale : 0), _y, 0);
        gl.glTranslated(w / 2 * (_flip ? -1 : 1) * _scale,
                h / 2 * _scale, 0);
        gl.glRotated(_rotation, 0, 0, 1);
        gl.glTranslated(-(w / 2 * (_flip ? -1 : 1) * _scale),
                -(h / 2 * _scale), 0);
        gl.glScaled((_flip ? -1 : 1) * _scale, _scale, 1);
        gl.glDisable(lastTarget);
        double rgb = 255 * color / 9; rgb /= 255.0;
        gl.glColor4d(rgb, rgb, rgb, _alpha / 255.0);
        gl.glBegin(GL.GL_QUADS);
        gl.glVertex2d(0, 0);
        gl.glVertex2d(0, h);
        gl.glVertex2d(w, h);
        gl.glVertex2d(w, 0);
        gl.glEnd();
        gl.glColor4d(1, 1, 1, 1);
        gl.glEnable(lastTarget);
        gl.glPopMatrix();
    }

    @Override
    public void drawSprite(Sprite s) {
        OpenGLSprite sprite = (OpenGLSprite) s;
        if (sprite.getTexture() == null) {
            Log.warn("Null texture, skipping...");
            return;
        }
        GL gl = GLU.getCurrentGL();
        gl.glPushMatrix();
        gl.glTranslated(_x + (_flip ? sprite.getWidth() * _scale : 0), _y, 0);
        gl.glTranslated(sprite.getWidth() / 2 * (_flip ? -1 : 1) * _scale,
                sprite.getHeight() / 2 * _scale, 0);
        gl.glRotated(_rotation, 0, 0, 1);
        gl.glTranslated(-(sprite.getWidth() / 2 * (_flip ? -1 : 1) * _scale),
                -(sprite.getHeight() / 2 * _scale), 0);
        gl.glScaled((_flip ? -1 : 1) * _scale, _scale, 1);
        Texture t = sprite.getTexture();
        TextureCoords tc = t.getImageTexCoords();
        float top = tc.top(), bottom = tc.bottom(), left = tc.left(), right = tc.right();
        int width = sprite.getWidth(), height = sprite.getHeight();
        if (lastTarget != t.getTarget()) {
            if (lastTarget != 0)
                gl.glDisable(lastTarget);
            t.enable();
        }
        t.bind();
        gl.glColor4d(1, 1, 1, _alpha / 255.0);
        gl.glBegin(GL.GL_QUADS);
        gl.glTexCoord2f(left, top); gl.glVertex2d(0, 0);
        gl.glTexCoord2f(left, bottom); gl.glVertex2d(0, height);
        gl.glTexCoord2f(right, bottom); gl.glVertex2d(width, height);
        gl.glTexCoord2f(right, top); gl.glVertex2d(width, 0);
        gl.glEnd();
        gl.glColor4d(1, 1, 1, 1);
        gl.glPopMatrix();
        lastTarget = t.getTarget();
    }

    @Override
    public boolean takeScreenshot(String screenshotName) {
        try {
            GLU.getCurrentGL();
        } catch (GLException ex) {
            synchronized (screenshots) {
                screenshots.add(screenshotName);
            }
            return false;
        }
        try {
            Screenshot.writeToFile(new File(screenshotName), 800, 600);
            return true;
        } catch (IOException ex) {
            Log.error("Could not write to screenshot: %s", ex.getMessage());
        } catch (GLException ex) {
            Log.error("OpenGL error, could not create screenshot: %s", ex.getMessage());
        }
        return false;
    }

    @Override
    public void unClip() {
        GL gl = GLU.getCurrentGL();
        gl.glDisable(GL.GL_SCISSOR_TEST);
    }

    public void drawDebugRect(int x, int y, int w, int h) {
        x += _x; y += _y;
        GL gl = GLU.getCurrentGL();
        gl.glDisable(lastTarget);
        gl.glColor4d(0, 1, 0, .5);
        gl.glBegin(GL.GL_QUADS);
        gl.glVertex2d(x, y);
        gl.glVertex2d(x, y + h);
        gl.glVertex2d(x + w, y + h);
        gl.glVertex2d(x + w, y);
        gl.glEnd();
        gl.glColor4d(1, 1, 1, 1);
        gl.glEnable(lastTarget);

    }

    @Override
    public void uploadSprites() {
        synchronized (texturesToLoad) {
            for (OpenGLSprite s : texturesToLoad)
                s.uploadTexture();
            texturesToLoad.clear();
        }
        synchronized (screenshots) {
            for (String str : screenshots)
                takeScreenshot(str);
            screenshots.clear();
        }
    }

}
